interface DownloadReq {
  start: number;
  end: number;
}
class Downloader {
  public state: boolean = false;
  private downloadList: Array<DownloadReq> = [];
  private step: number = 0;
  private url = "";
  constructor() {}

  //合并缓冲区
  appendBuffer(buffer1: ArrayBuffer, buffer2: ArrayBuffer): ArrayBuffer {
    let tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
    tmp.set(new Uint8Array(buffer1), 0);
    tmp.set(new Uint8Array(buffer2), buffer1.byteLength);
    return tmp.buffer;
  }

  // 报告文件大小
  reportFileSize(sz: number, st: number) {
    let objData = {
      t: 0,
      i: {
        sz: sz,
        st: st,
      },
    };

    // 发送文件大小和状态信息
    self.postMessage(objData);
  }

  //查询数据信息
  reportData(data: ArrayBuffer) {
    let objData: any = {
      t: 1,
      d: data,
    };
    // 发送数据
    self.postMessage(objData);
  }

  //获取文件信息
  getFileInfoByHttp(url: string) {
    let size: number = 0;
    let status = 0;
    let reported = false;

    let xhr = new XMLHttpRequest();
    xhr.open("get", url, true);

    xhr.onreadystatechange = () => {
      let len = xhr.getResponseHeader("Content-Length");
      if (len) {
        size = len;
      }

      if (xhr.status) {
        status = xhr.status;
      }

      // 当文件大小和状态已知或请求已完成时报告
      if (!reported && ((size > 0 && status > 0) || xhr.readyState == 4)) {
        this.reportFileSize(size, status);
        reported = true;
        xhr.abort(); // 中断请求
      }
    };
    xhr.send();
  }
  // 下载文件
  download(start: number, end: number) {
    return new Promise<ArrayBuffer>((resolve, reject) => {
      var xhr = new XMLHttpRequest();
      xhr.open("get", this.url, true);
      xhr.responseType = "arraybuffer";
      xhr.setRequestHeader("Range", "bytes=" + start + "-" + end);
      var self = this;
      xhr.onload = function () {
        resolve(xhr.response);
        // self.reportData(start, end, seq, xhr.response);
      };
      xhr.onerror = (err) => {
        reject(err);
      };
      xhr.send();
    });
  }

  public getFileInfo() {
    this.getFileInfoByHttp(this.url);
  }
  public async downloadFile(start: number, end: number) {
    if (this.state) {
      this.downloadList.push({ start, end });
      return;
    }
    this.state = true;
    this.download(start, end).then((res) => {
      this.reportData(res);
      this.state = false;
      if (this.downloadList.length) {
        this.downloadFile(this.downloadList[0].start, this.downloadList[0].end);
        this.downloadList.shift();
      }
    });
  }

  init(url: string) {
    this.url = url;
  }
}
// 实例化下载器
let downloader = new Downloader();

// 处理来自主线程的消息
self.onmessage = function (evt) {
  if (!downloader) {
    console.log("[ER] Downloader not initialized!");
    return;
  }

  var objData = evt.data;

  switch (objData.t) {
    case 0:
      downloader.getFileInfo();
      break;
    case 1:
      downloader.downloadFile(objData.s, objData.e);
      break;
    default:
      downloader.init(objData.u);
  }
};

self.postMessage("[OK] Downloader initialized!");
